{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#!/usr/bin/python\n",
    "# find . -name '.DS_Store' -type f -delete\n",
    "# Chulwoo Pack\n",
    "\n",
    "import sys\n",
    "import os\n",
    "from page import Page\n",
    "\n",
    "SHOW_STEPS = True    # change this to false if you just want to see the final output for each page.\n",
    "SAVE_OUTPUT = True\n",
    "SAVE_DOCSTRUM = True\n",
    "\n",
    "inputFolder = os.path.join('images')\n",
    "outputFolder = os.path.join('output')\n",
    "\n",
    "    \n",
    "inputPath = os.path.join(inputFolder, os.listdir(inputFolder)[0])\n",
    "outputPath = os.path.join(outputFolder, os.listdir(inputFolder)[0])\n",
    "\n",
    "page = Page(inputPath, SHOW_STEPS, SAVE_DOCSTRUM)\n",
    "#page = Page(inputPath, SHOW_STEPS)\n",
    "    \n",
    "if SAVE_OUTPUT:\n",
    "    page.save(outputPath)  # save a copy of what is displayed. Used for getting images for the paper.\n",
    "    \n",
    "page.show((800, 800))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "# LINE EXTRACTION TESTING\n",
    "\n",
    "import sys\n",
    "import os\n",
    "from page import Page\n",
    "\n",
    "import cv2\n",
    "import math\n",
    "import numpy\n",
    "import subprocess\n",
    "import os\n",
    "\n",
    "import colors\n",
    "import geometry as g\n",
    "from box import Box\n",
    "import text\n",
    "from dimension import Dimension\n",
    "from stopwatch import Stopwatch\n",
    "import numpy\n",
    "import matplotlib.pyplot as plt\n",
    "import ntpath\n",
    "\n",
    "\n",
    "SHOW_STEPS = True    # change this to false if you just want to see the final output for each page.\n",
    "SAVE_OUTPUT = True\n",
    "SAVE_DOCSTRUM = False\n",
    "\n",
    "inputFolder = os.path.join('images')\n",
    "outputFolder = os.path.join('output')\n",
    "\n",
    "    \n",
    "inputPath = os.path.join(inputFolder, os.listdir(inputFolder)[0])\n",
    "outputPath = os.path.join(outputFolder, os.listdir(inputFolder)[0])\n",
    "\n",
    "page = Page(inputPath, SHOW_STEPS, SAVE_DOCSTRUM)\n",
    "\n",
    "\n",
    "if True:\n",
    "    page.save(outputPath)  # save a copy of what is displayed. Used for getting images for the paper.\n",
    "    \n",
    "page.show((800, 800))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "print(\"%.2f\" %1.237)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "for line in page.lines:\n",
    "    line.group = None\n",
    "\n",
    "for line in page.lines:\n",
    "    print(line.group)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#NER VERSION: ADJUSTIVE SEARCHING ORDER\n",
    "import cv2\n",
    "\n",
    "from shapely.geometry import Point            # For checking overlap\n",
    "from shapely.geometry.polygon import Polygon  # For checking overlap\n",
    "from shapely.geometry import MultiPoint       # For checking overlap\n",
    "\n",
    "import progressbar      # For displaying progressbar\n",
    "from time import sleep  # For displaying progressbar\n",
    "\n",
    "#from stopwatch import Stopwatch   # For checking run-time\n",
    "\n",
    "#stopwatch = Stopwatch()\n",
    "\n",
    "image = page.image.copy()\n",
    "\n",
    "EPS = 1e-10\n",
    "group_idx = 0\n",
    "threshold_angle = 1.0\n",
    "threshold_paralldist = 1.7 * 13.0\n",
    "threshold_perpendist = 1.7 * 17.0 #[1.5~1.7]\n",
    "threshold_overlap    = 1.0\n",
    "threshold_early_skip = 100\n",
    "threshold_visualize_line_width = 5\n",
    "\n",
    "SHOW_DETAIL      = False\n",
    "SHOW_VISUAL_STEP = True\n",
    "EARLY_SKIP       = False\n",
    "\n",
    "########\n",
    "# INIT #\n",
    "########\n",
    "# Get lines\n",
    "_my_lines  = page.lines\n",
    "# Remove dots\n",
    "my_lines = []\n",
    "for _my_line in _my_lines:\n",
    "    if(_my_line.start.x-_my_line.end.x==0 and _my_line.start.y-_my_line.end.y==0):\n",
    "        continue\n",
    "    else:\n",
    "        my_lines.append(_my_line)\n",
    "# Sorting lines\n",
    "my_lines.sort(key=lambda line:((line.start.y+line.end.y)/2,(line.start.x+line.end.x)/2))\n",
    "# Lines assigned a group\n",
    "my_lines_in_group = []\n",
    "# Lines not assigned any group yet\n",
    "my_lines_no_group = []\n",
    "for i in range(0,len(my_lines)-1):\n",
    "    my_lines_no_group.append(i)\n",
    "if SHOW_DETAIL: print(\"no_group:\",my_lines_in_group)\n",
    "if SHOW_DETAIL: print(\"in_group:\",my_lines_no_group)\n",
    "# First line, not dot (its index, i)\n",
    "\n",
    "bar = progressbar.ProgressBar(maxval=len(my_lines_no_group), \\\n",
    "            widgets=[progressbar.Bar('=', '[', ']'), ' ', progressbar.Percentage()])\n",
    "progress_idx = 0\n",
    "bar.start()\n",
    "\n",
    "max_loop = len(my_lines)\n",
    "#act_loop = 0\n",
    "\n",
    "for act_loop in xrange(max_loop): # Make sure looked up every lines   \n",
    "    #flag_found_none = True\n",
    "    if ((len(my_lines_in_group) == 0) and (len(my_lines_no_group) == 0)):\n",
    "        break\n",
    "    #test_act_loop = test_act_loop+1\n",
    "    \n",
    "    progress_idx = progress_idx+2 # Update progressbar\n",
    "    bar.update(act_loop)      # Update progressbar\n",
    "    sleep(0.1)    \n",
    "    #######################\n",
    "    # Set the ith element #\n",
    "    #######################\n",
    "    i = -1\n",
    "    if EARLY_SKIP:\n",
    "        early_skip = threshold_early_skip\n",
    "    ## TODO: Since, currently there is no lines in my_lines_in_group queue and lines are remained, find another line as ith element in my_lines_no_group queue with excluding dots. \n",
    "    if(len(my_lines_in_group) == 0):\n",
    "        delta_x_i = 0\n",
    "        delta_y_i = 0\n",
    "        for candidate_line_idx in my_lines_no_group[:]:\n",
    "            x_O_i = my_lines[candidate_line_idx].start.x\n",
    "            y_O_i = page.image.shape[0] - my_lines[candidate_line_idx].start.y\n",
    "            x_F_i = my_lines[candidate_line_idx].end.x\n",
    "            y_F_i = page.image.shape[0] - my_lines[candidate_line_idx].end.y \n",
    "            #delta_x_i = abs(x_F_i - x_O_i)\n",
    "            delta_x_i = float(x_F_i - x_O_i)\n",
    "            #delta_y_i = abs(y_F_i - y_O_i)\n",
    "            delta_y_i = float(y_F_i - y_O_i)\n",
    "            if (delta_x_i != 0 and delta_y_i != 0): # Found!\n",
    "                i = candidate_line_idx\n",
    "                my_lines_no_group.remove(candidate_line_idx)\n",
    "                break\n",
    "    else:\n",
    "        i = my_lines_in_group.pop(0)\n",
    "        \n",
    "    \n",
    "    # TODO: more sophisticated way to break?\n",
    "    if (i == -1):\n",
    "        break\n",
    "    \n",
    "    # Visualize ith element\n",
    "    if SHOW_VISUAL_STEP:\n",
    "        image = page.image.copy()\n",
    "        cv2.line(image, ((my_lines[i].start.x,my_lines[i].start.y)),((my_lines[i].end.x,my_lines[i].end.y)), (0,0,255),threshold_visualize_line_width)\n",
    "        page.display(image, title='Visualization of text-line groupping step')\n",
    "                                                       \n",
    "    # No more lines to search\n",
    "    if (len(my_lines_no_group) == 0):\n",
    "        break\n",
    "    else:\n",
    "        my_lines[i].noise = False  # This assure that dot-wise noise to be excluded from grouping process\n",
    "        #######################\n",
    "        # Set the jth element #\n",
    "        #######################\n",
    "        for j in my_lines_no_group[:]:\n",
    "            if EARLY_SKIP:\n",
    "                if early_skip < 0:\n",
    "                    break\n",
    "            if SHOW_VISUAL_STEP:\n",
    "                cv2.line(image, ((my_lines[j].start.x,my_lines[j].start.y)),((my_lines[j].end.x,my_lines[j].end.y)), (255,0,0),threshold_visualize_line_width)\n",
    "                page.display(image, title='Visualization of text-line groupping step')\n",
    "\n",
    "            sameGroup = False\n",
    "            ################################\n",
    "            # CALCULATE GEOMETRIC FEATURES #\n",
    "            ################################\n",
    "            # Point setting\n",
    "            x_O_i = my_lines[i].start.x\n",
    "            y_O_i = page.image.shape[0] - my_lines[i].start.y\n",
    "            x_F_i = my_lines[i].end.x\n",
    "            y_F_i = page.image.shape[0] - my_lines[i].end.y \n",
    "\n",
    "            x_O_j = my_lines[j].start.x\n",
    "            y_O_j = page.image.shape[0] - my_lines[j].start.y\n",
    "            x_F_j = my_lines[j].end.x\n",
    "            y_F_j = page.image.shape[0] - my_lines[j].end.y\n",
    "\n",
    "            #delta_x_i = abs(x_F_i - x_O_i)\n",
    "            #delta_y_i = abs(y_F_i - y_O_i)\n",
    "            #delta_x_j = abs(x_F_j - x_O_j)\n",
    "            #delta_y_j = abs(y_F_j - y_O_j)\n",
    "            delta_x_i = float(x_F_i - x_O_i)\n",
    "            delta_y_i = float(y_F_i - y_O_i)\n",
    "            delta_x_j = float(x_F_j - x_O_j)\n",
    "            delta_y_j = float(y_F_j - y_O_j)\n",
    "            \n",
    "            \n",
    "            # ith or jth line is dot, so skip it\n",
    "            if (delta_x_j == 0 and delta_y_j == 0):\n",
    "                my_lines_no_group.remove(j)\n",
    "                continue\n",
    "\n",
    "            if SHOW_DETAIL:\n",
    "                print(\"\\n****************************************************************\")\n",
    "                print(\"# of in_group:\",len(my_lines_in_group),my_lines_in_group)\n",
    "                print(\"# of no_group:\",len(my_lines_no_group),my_lines_no_group)\n",
    "                print(i, my_lines[i].points)\n",
    "                print(j, my_lines[j].points)\n",
    "                print(\"i:\",x_O_i,y_O_i,\"-\",x_F_i,y_F_i)\n",
    "                print(\"j:\",x_O_j,y_O_j,\"-\",x_F_j,y_F_j)\n",
    "\n",
    "            # Calculate angle\n",
    "            theta_i_j = math.atan2(delta_y_j,delta_x_j-math.atan2(delta_y_i,delta_x_i))\n",
    "            if SHOW_DETAIL:\n",
    "                print(\"Angle:\",theta_i_j)\n",
    "\n",
    "            # Calculate overlap\n",
    "            #if delta_x_j == 0:\n",
    "            #    delta_x_j = 0.1\n",
    "            #if delta_y_i == 0:\n",
    "            #    delta_y_i = 0.1\n",
    "            #if delta_y_j == 0:\n",
    "            #    delta_y_j = 0.1\n",
    "            #if delta_x_i == 0:\n",
    "            #    delta_x_i = 0.1\n",
    "\n",
    "\n",
    "            x_A_j = (x_O_i*delta_x_i*delta_x_j + x_O_j*delta_y_i*delta_y_j + delta_x_j*delta_y_i*(y_O_i-y_O_j))/(delta_y_i*delta_y_j + delta_x_i*delta_x_j + EPS)\n",
    "            if (delta_x_j != 0):\n",
    "                y_A_j = (delta_y_j/delta_x_j)*(x_A_j - x_O_j) + y_O_j\n",
    "            else:\n",
    "                x_A_j = y_O_j\n",
    "\n",
    "            x_B_j = (x_F_i*delta_x_i*delta_x_j + x_F_j*delta_y_i*delta_y_j + delta_x_j*delta_y_i*(y_F_i-y_F_j))/(delta_y_i*delta_y_j + delta_x_i*delta_x_j + EPS)\n",
    "            if (delta_x_j != 0):\n",
    "                y_B_j = (delta_y_j/delta_x_j)*(x_B_j - x_F_j) + y_F_j\n",
    "            else:\n",
    "                x_B_j = y_F_j\n",
    "\n",
    "            # Find C and D ponts\n",
    "            #x_middle_candidates = [x_O_j, x_F_j, x_A_j, x_B_j]\n",
    "            #x_middle_candidates.sort()\n",
    "            #y_middle_candidates = [y_O_j, y_F_j, y_A_j, y_B_j]\n",
    "            #y_middle_candidates.sort()\n",
    "            C_D_candidates = [(x_O_j,y_O_j), (x_F_j,y_F_j), (x_A_j,y_A_j), (x_B_j,y_B_j)]\n",
    "            if (delta_x_j != 0):\n",
    "                C_D_candidates.sort(key=lambda x:x[0]) # sort by x\n",
    "            elif (delta_y_j != 0):\n",
    "                C_D_candidates.sort(key=lambda x:x[1]) # sort by y\n",
    "            x_C_j,y_C_j = C_D_candidates[1]\n",
    "            x_D_j,y_D_j = C_D_candidates[2]\n",
    "\n",
    "            if SHOW_DETAIL:\n",
    "                print(\"x_A_j,y_A_j\",x_A_j,y_A_j)\n",
    "                print(\"x_B_j,y_B_j\",x_B_j,y_B_j)\n",
    "                print(\"x_C_j,y_C_j\",x_C_j,y_C_j)\n",
    "                print(\"x_D_j,y_D_j\",x_D_j,y_D_j)\n",
    "\n",
    "            #x_i_j_components = [int(x_O_i), int(x_F_i), int(x_O_j), int(x_F_j)]\n",
    "            #x_i_j_components.sort()\n",
    "            #y_i_j_components = [int(y_O_i), int(y_F_i), int(y_O_j), int(y_F_j)]\n",
    "            #y_i_j_components.sort()\n",
    "            # convert to int in order to allow generous overlap\n",
    "            #if ((int(x_O_j) <= int(x_C_j) <= int(x_F_j) and (int(y_O_j) <= int(y_C_j) <= int(y_F_j) or int(y_F_j) <= int(y_C_j) <= int(y_O_j))) or (int(x_O_i) <= int(x_C_j) <= int(x_F_i) and (int(y_O_i) <= int(x_C_j) <= int(y_F_i) or int(y_F_i) <= int(y_C_j) <= int(y_O_i)))) and ((int(x_O_j) <= int(x_D_j) <= int(x_F_j) and (int(y_O_j) <= int(y_D_j) <= int(y_F_j) or int(y_F_j) <= int(y_D_j) <= int(y_O_j))) or (int(x_O_i) <= int(x_D_j) <= int(x_F_i) and (int(y_O_i) <= int(y_D_j) <= int(y_F_i) or int(y_F_i) <= int(y_D_j) <= int(y_O_i)))):\n",
    "            #if ((x_i_j_components[0] <= int(x_C_j[0]) <= x_i_j_components[-1]) and (y_i_j_components[0] <= int(y_C_j) <= y_i_j_components[-1]) and (x_i_j_components[0] <= int(x_D_j) <= x_i_j_components[-1]) and (y_i_j_components[0] <= int(y_D_j) <= y_i_j_components[-1])):\n",
    "            #convex_hull = MultiPoint([(x_O_j, y_O_j), (x_O_j, y_F_j), (x_F_j, y_F_j), (x_F_j, y_O_j)])\n",
    "            #polygon = Polygon([(x_O_i, y_O_i), (x_F_i, y_F_i),(x_F_j, y_F_j), (x_O_j, y_O_j)])\n",
    "            #convex_hull = MultiPoint([(x_O_i, y_O_i), (x_F_i, y_F_i),(x_F_j, y_F_j), (x_O_j, y_O_j)]).convex_hull\n",
    "            polygon = Polygon([(x_O_j, y_O_j), (x_O_j, y_F_j), (x_F_j, y_F_j), (x_F_j, y_O_j)])\n",
    "            C_point = Point(x_C_j, y_C_j)\n",
    "            D_point = Point(x_D_j, y_D_j)\n",
    "            #if polygon.area != convex_hull.area:\n",
    "            #    overlap = False\n",
    "            #elif (convex_hull.contains(C_point) and convex_hull.contains(D_point)):\n",
    "            #if (convex_hull.contains(C_point) and convex_hull.contains(D_point)):\n",
    "            if (polygon.contains(C_point) or polygon.touches(C_point)) and (polygon.contains(D_point) or polygon.touches(D_point)):\n",
    "                overlap = True\n",
    "            else:\n",
    "                overlap = False\n",
    "            \n",
    "            #p_j = (math.sqrt(math.pow(y_D_j-y_C_j,2)+math.pow(x_D_j-x_C_j,2)))/2.0\n",
    "            p_j = math.sqrt(math.pow(y_D_j-y_C_j,2)+math.pow(x_D_j-x_C_j,2))\n",
    "            l_j = math.sqrt(math.pow(y_F_j-y_O_j,2)+math.pow(x_F_j-x_O_j,2))\n",
    "            if (l_j == 0):\n",
    "                l_j = 0.1\n",
    "            if overlap:\n",
    "                p_i_j = p_j/l_j\n",
    "            else:\n",
    "                p_i_j = -p_j/l_j\n",
    "\n",
    "            if SHOW_DETAIL:\n",
    "                print(\"Overlap?\",overlap)\n",
    "                print(\"p_j:\",p_j)\n",
    "                print(\"p_i_j:\",p_i_j)\n",
    "\n",
    "            # Calculate parallel_dist\n",
    "            if overlap:\n",
    "                d_i_j_a = p_j\n",
    "            else:\n",
    "                d_i_j_a = -p_j\n",
    "            if SHOW_DETAIL:\n",
    "                print(\"parallel_dist: \",d_i_j_a)\n",
    "\n",
    "            # Calculate perpend_dist\n",
    "            x_M_j = (x_C_j + x_D_j)/2.0\n",
    "            y_M_j = (y_C_j + y_D_j)/2.0\n",
    "            if SHOW_DETAIL:\n",
    "                print(\"x_M_j,y_M_j\",x_M_j,y_M_j)\n",
    "                print(\"delta_x_i:\",delta_x_i)\n",
    "                print(\"delta_y_i:\",delta_y_i)\n",
    "                print(\"delta_x_j:\",delta_x_j)\n",
    "                print(\"delta_y_j:\",delta_y_j)\n",
    "\n",
    "            if delta_x_i != 0.0 and delta_y_i != 0.0:\n",
    "                d_e_i_j = ((x_M_j - x_O_i) - (y_M_j - y_O_i)*delta_x_i/(delta_y_i + EPS))/((delta_x_i**2)/(delta_y_i**2 + EPS) + 1)**0.5 \n",
    "            elif delta_y_i == 0.0:\n",
    "                d_e_i_j = int(y_M_j) - int(y_O_i)\n",
    "            elif delta_x_i == 0.0:\n",
    "                d_e_i_j = int(x_M_j) - int(x_O_i)\n",
    "            d_e_i_j = abs(d_e_i_j)\n",
    "\n",
    "            if SHOW_DETAIL:\n",
    "                print(\"perpend_dist: \",d_e_i_j)\n",
    "\n",
    "            ######################\n",
    "            # DECIDING GROUPNESS #\n",
    "            #######################\n",
    "            # 1. angle check\n",
    "            if theta_i_j < threshold_angle:\n",
    "                if SHOW_DETAIL: print(\"... Angle ok!\")\n",
    "            # 2. perpend_dist check\n",
    "                if 0 < d_e_i_j < threshold_perpendist:\n",
    "                    if SHOW_DETAIL: print(\"... Perpendicular ok!\")\n",
    "            # 3.a. overlap check\n",
    "            # 3.b. parallel_dist check\n",
    "                    if ((overlap and p_i_j <= threshold_overlap)):\n",
    "                        if SHOW_DETAIL: print(\"... Overlap & p_i_j ok!\")\n",
    "                        # Group!\n",
    "                        sameGroup = True\n",
    "                    elif (abs(d_i_j_a) < threshold_paralldist):\n",
    "                        if SHOW_DETAIL: print(\"... Parallel ok!\")\n",
    "                        # Group!\n",
    "                        sameGroup = True\n",
    "\n",
    "            if SHOW_DETAIL:\n",
    "                print(\"same group? \",sameGroup)\n",
    "            if sameGroup:\n",
    "\n",
    "                if EARLY_SKIP:\n",
    "                    early_skip = threshold_early_skip\n",
    "                if SHOW_DETAIL:\n",
    "                    print(\"before group idx: \",group_idx)\n",
    "                    print(\"before i's group: \", my_lines[i].group)\n",
    "                    print(\"before j's group: \", my_lines[j].group)\n",
    "                if (my_lines[i].group == None) and (my_lines[j].group == None):\n",
    "                    if SHOW_DETAIL:\n",
    "                        print(\"... case 1\")\n",
    "                    # Assign to a new block\n",
    "                    group_idx = group_idx + 1\n",
    "                    my_lines[i].group = group_idx\n",
    "                    my_lines[j].group = group_idx\n",
    "                    #my_lines_no_group.remove(i)     # update queue\n",
    "                    my_lines_in_group.append(i)     # update queue\n",
    "                    my_lines_no_group.remove(j)     # update queue\n",
    "                    my_lines_in_group.append(j)     # update queue\n",
    "                elif (my_lines[i].group == None):\n",
    "                    if SHOW_DETAIL: print(\"... case 2\")\n",
    "                    # Unassigned text-line is assigned to the block of the other\n",
    "                    my_lines[i].group = my_lines[j].group\n",
    "                    #my_lines_no_group.remove(i)     # update queue\n",
    "                    my_lines_in_group.append(i)     # update queue\n",
    "                elif (my_lines[j].group == None):\n",
    "                    if SHOW_DETAIL: print(\"... case 3\")\n",
    "                    # Unassigned text-line is assigned to the block of the other\n",
    "                    my_lines[j].group = my_lines[i].group\n",
    "                    my_lines_no_group.remove(j)     # update queue\n",
    "                    my_lines_in_group.append(j)     # update queue\n",
    "                if SHOW_DETAIL: print(\"after group idx: \",group_idx)\n",
    "                if SHOW_DETAIL: print(\"after i's group: \", my_lines[i].group)\n",
    "                if SHOW_DETAIL: print(\"after j's group: \", my_lines[j].group)\n",
    "                if SHOW_VISUAL_STEP:\n",
    "                    cv2.line(image, ((my_lines[j].start.x,my_lines[j].start.y)),((my_lines[j].end.x,my_lines[j].end.y)), (0,255,0),threshold_visualize_line_width)\n",
    "                    page.display(image, title='Visualization of text-line groupping step')\n",
    "            else:\n",
    "                if EARLY_SKIP:\n",
    "                    early_skip = early_skip - 1\n",
    "            \n",
    "        if (my_lines[i].noise == False and my_lines[i].group == None):\n",
    "            group_idx = group_idx + 1\n",
    "            my_lines[i].group = group_idx\n",
    "bar.finish()\n",
    "\n",
    "print(\"Total iter: [%d/%d]\" %(act_loop,max_loop))\n",
    "print(\"Done!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "\n",
    "dist = [10,20,20,50,20,20,30,25,25,25,25,25,25]\n",
    "n, bins, patches = plt.hist(dist, numpy.max(dist)-numpy.min(dist)+1, facecolor='orange', alpha=0.5)\n",
    "n_copy = n.copy()\n",
    "print(n)\n",
    "print(n_copy)\n",
    "n_copy[::-1].sort()\n",
    "print(n)\n",
    "print(n_copy)\n",
    "print(bins)\n",
    "print(numpy.argmax(n)+numpy.min(dist))\n",
    "print(bins.max())\n",
    "\n",
    "#n_copy[::-1].sort()\n",
    "a = numpy.where(n == n_copy[2])\n",
    "print(\"Test\",a)\n",
    "\n",
    "if len(a[0])>1:\n",
    "    _max = a[0][int(len(a[0])/2)]\n",
    "else:\n",
    "    _max = a[0][0]\n",
    "\n",
    "_max+numpy.min(dist)\n",
    "\n",
    "for i in range(5):\n",
    "    print(i)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "peakind = signal.find_peaks_cwt([10,20,20,50,20,20,30], np.arange(1,10))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "peakind"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "x_O_i = 491\n",
    "y_O_i = 615\n",
    "x_F_i = 757\n",
    "y_F_i = 600\n",
    "x_O_j = 491\n",
    "y_O_j = 615\n",
    "x_F_j = 757\n",
    "y_F_j = 600\n",
    "x_C_j = 757\n",
    "y_C_j = int(637.6500942238861)\n",
    "\n",
    "delta_y_j = 7.0\n",
    "delta_x_j = 658.0\n",
    "x_A_j = 4144.4503916449075\n",
    "x_F_j = 3890.0\n",
    "y_F_j = 1856.0\n",
    "(delta_y_j/delta_x_j)*(x_A_j - x_F_j) + y_F_j\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "('i:', 2639, 4875, '-', 2676, 4872)\n",
    "('j:', 992, 4892, '-', 2222, 4879)\n",
    "('Angle:', -0.010568017106413556)\n",
    "('x_A_j,y_A_j', 2638.9670025686564, 4874.593031680169)\n",
    "('x_B_j,y_B_j', 2676.178357373372, 4874.19974093833)\n",
    "('x_C_j,y_C_j', 2222, 4879)\n",
    "('x_D_j,y_D_j', 2638.9670025686564, 4874.593031680169)\n",
    "\n",
    "x_O_i = 2639\n",
    "y_O_i = 4875\n",
    "x_F_i = 2676\n",
    "y_F_i = 4872\n",
    "\n",
    "x_O_j = 896\n",
    "y_O_j = 4802\n",
    "x_F_j = 1415\n",
    "y_F_j = 4805\n",
    "\n",
    "x_C_j = 2222\n",
    "y_C_j = 4879\n",
    "x_D_j = 2638#.9670025686564\n",
    "y_D_j = 4874#.593031680169\n",
    "\n",
    "\n",
    "#polygon = Polygon([(x_O_i-1, y_O_i+1), (x_F_i+1, y_F_i+1),(x_F_j+1, y_F_j-1), (x_O_j-1, y_O_j-1)])\n",
    "polygon = Polygon([(x_O_i, y_O_i), (x_F_i, y_F_i),(x_F_j, y_F_j), (x_O_j, y_O_j)])\n",
    "#C_point = Point(x_C_j, y_C_j)\n",
    "#D_point = Point(x_D_j, y_D_j)\n",
    "polygon.area"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "from shapely.geometry import MultiPoint\n",
    "convex_hull = MultiPoint([(x_O_i, y_O_i), (x_F_i, y_F_i),(x_F_j, y_F_j), (x_O_j, y_O_j)]).convex_hull\n",
    "convex_hull.area"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "x_O_j = 2476\n",
    "y_O_j = 1938\n",
    "x_F_j = 2840\n",
    "y_F_j = 1932\n",
    "x_A_j = 2363\n",
    "y_A_j = 1939\n",
    "x_B_j = 2631\n",
    "y_B_j = 1935\n",
    "\n",
    "C_D_candidates = [(x_O_j,y_O_j), (x_F_j,y_F_j), (x_A_j,y_A_j), (x_B_j,y_B_j)]\n",
    "C_D_candidates.sort(key=lambda x:x[0])\n",
    "print(C_D_candidates[1])\n",
    "print(C_D_candidates[2])\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "C_D_candidates"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "C_D_candidates"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "C_x,C_y = C_D_candidates[1]\n",
    "print(C_x)\n",
    "print(C_y)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "Polygon([(0-1, y_O_i+1), (x_F_i+1, y_F_i+1),(x_F_j+1, y_F_j-1), (x_O_j-1, y_O_j-1)])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "######################\n",
    "# Draw Grouped Lines #\n",
    "######################\n",
    "import cv2\n",
    "image = page.image.copy()\n",
    "for my_line in my_lines:\n",
    "    #print(my_line.start.x)\n",
    "#    print my_line.group\n",
    "    if my_line.group == None:\n",
    "        continue\n",
    "        blue  = 0\n",
    "        green = 0 \n",
    "        red   = 0\n",
    "    else:\n",
    "        blue = (my_line.group*100)%255\n",
    "        green = (my_line.group*200)%255\n",
    "        red = (my_line.group*300)%255\n",
    "        \n",
    "    #print(blue,green,red)\n",
    "    cv2.line(image, (my_line.start.x,my_line.start.y), (my_line.end.x,my_line.end.y), (blue,green,red),10)\n",
    "    \n",
    "#cv2.imwrite(outputPath, image) \n",
    "maxDimension = Dimension(800, 800)\n",
    "displayDimension = Dimension(image.shape[1], image.shape[0])\n",
    "displayDimension.fitInside(maxDimension)\n",
    "image = cv2.resize(image, tuple(displayDimension))\n",
    "cv2.namedWindow('title', cv2.CV_WINDOW_AUTOSIZE)\n",
    "cv2.imshow('grouped', image)\n",
    "cv2.waitKey()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#######################\n",
    "# Draw Bounding Boxes #\n",
    "#######################\n",
    "import cv2\n",
    "import numpy\n",
    "THRESHOLD_POLY_EXAGGERATE = 10 # Unit: Pixel\n",
    "image = page.image.copy()\n",
    "tot_groups = group_idx+1\n",
    "group_table = []\n",
    "for group_idx in range(tot_groups):\n",
    "    group_table.append([])\n",
    "\n",
    "for my_line in my_lines:\n",
    "    for group_idx in range(1,tot_groups):\n",
    "        if my_line.group == None:\n",
    "            continue\n",
    "        elif my_line.group == group_idx:\n",
    "            exaggerated_left_start_x   = my_line.start.x-THRESHOLD_POLY_EXAGGERATE\n",
    "            exaggerated_up_start_y     = my_line.start.y+THRESHOLD_POLY_EXAGGERATE\n",
    "            exaggerated_down_start_y   = my_line.start.y-THRESHOLD_POLY_EXAGGERATE\n",
    "            \n",
    "            exaggerated_right_end_x    = my_line.end.x+THRESHOLD_POLY_EXAGGERATE\n",
    "            exaggerated_up_end_y       = my_line.end.y+THRESHOLD_POLY_EXAGGERATE\n",
    "            exaggerated_down_end_y     = my_line.end.y-THRESHOLD_POLY_EXAGGERATE\n",
    "            \n",
    "            group_table[group_idx-1].append([exaggerated_left_start_x,exaggerated_up_start_y])\n",
    "            group_table[group_idx-1].append([exaggerated_left_start_x,exaggerated_down_start_y])\n",
    "            \n",
    "            group_table[group_idx-1].append([exaggerated_right_end_x,exaggerated_up_end_y])\n",
    "            group_table[group_idx-1].append([exaggerated_right_end_x,exaggerated_down_end_y])\n",
    "            \n",
    "            \n",
    "\n",
    "for group_idx in range(1,tot_groups):\n",
    "    points = numpy.array(group_table[group_idx-1], dtype='int')\n",
    "    rect = cv2.minAreaRect(points)\n",
    "    box = cv2.cv.BoxPoints(rect) # cv2.boxPoints(rect) for OpenCV 3.x\n",
    "    box = numpy.int0(box)\n",
    "    cv2.drawContours(image,numpy.int32([box]),0,(0,0,255),7)\n",
    "    #convex_hull = cv2.convexHull(points)\n",
    "    #cv2.polylines(image, numpy.int32([convex_hull]), True, (0, 0, 255), thickness=2)\n",
    "\n",
    "\n",
    "maxDimension = Dimension(800, 800)\n",
    "displayDimension = Dimension(image.shape[1], image.shape[0])\n",
    "displayDimension.fitInside(maxDimension)\n",
    "image = cv2.resize(image, tuple(displayDimension))\n",
    "cv2.namedWindow('Polylines', cv2.CV_WINDOW_AUTOSIZE)\n",
    "cv2.imshow('Polylines', image)\n",
    "cv2.waitKey()\n",
    "cv2.destroyAllWindows()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "cv2.imwrite(outputPath, image)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "group_table"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "cv2.imwrite(outputPath, image)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "################################\n",
    "# Draw BoundingBox (Rectangle) #\n",
    "################################\n",
    "import cv2\n",
    "import numpy\n",
    "image = page.image.copy()\n",
    "boundingbox_table = numpy.zeros((group_idx+1,4))  # [min_x,max_x,min_y,max_y]\n",
    "boundingbox_table[:,0] = image.shape[1]\n",
    "boundingbox_table[:,1] = 0\n",
    "boundingbox_table[:,2] = image.shape[0]\n",
    "boundingbox_table[:,3] = 0\n",
    "\n",
    "# Find BoundingBoxes for Each Group\n",
    "for my_line in my_lines:\n",
    "    for i in range(1,group_idx+1):\n",
    "        if my_line.group == None:\n",
    "            # Update if found new min or max\n",
    "            if my_line.start.x < boundingbox_table[-1,0]:\n",
    "                boundingbox_table[-1,0] = my_line.start.x\n",
    "            if my_line.end.x > boundingbox_table[-1,1]:\n",
    "                boundingbox_table[-1,1] = my_line.end.x\n",
    "            if my_line.start.y < boundingbox_table[-1,2]:\n",
    "                boundingbox_table[-1,2] = my_line.start.y\n",
    "            if my_line.end.y > boundingbox_table[-1,3]:\n",
    "                boundingbox_table[-1,3] = my_line.end.y\n",
    "        elif my_line.group == i:\n",
    "            # Update if found new min or max\n",
    "            if my_line.start.x < boundingbox_table[i-1,0]:\n",
    "                boundingbox_table[i-1,0] = my_line.start.x\n",
    "            if my_line.end.x > boundingbox_table[i-1,1]:\n",
    "                boundingbox_table[i-1,1] = my_line.end.x\n",
    "            if my_line.start.y < boundingbox_table[i-1,2]:\n",
    "                boundingbox_table[i-1,2] = my_line.start.y\n",
    "            if my_line.end.y > boundingbox_table[i-1,3]:\n",
    "                boundingbox_table[i-1,3] = my_line.end.y\n",
    "                \n",
    "# Draw BoundingBoxes \n",
    "for i in range(group_idx+1):\n",
    "    x_min = int(boundingbox_table[i,0])\n",
    "    x_max = int(boundingbox_table[i,1])\n",
    "    y_min = int(boundingbox_table[i,2])\n",
    "    y_max = int(boundingbox_table[i,3])\n",
    "    cv2.rectangle(image,(x_min,y_max),(x_max,y_min),(0,0,255),5) # (image, Top-Left, Bottom-Right, BGR_Color, Width)\n",
    "\n",
    "\n",
    "maxDimension = Dimension(800, 800)\n",
    "displayDimension = Dimension(image.shape[1], image.shape[0])\n",
    "displayDimension.fitInside(maxDimension)\n",
    "image = cv2.resize(image, tuple(displayDimension))\n",
    "cv2.namedWindow('title', cv2.CV_WINDOW_AUTOSIZE)\n",
    "cv2.imshow('grouped', image)\n",
    "cv2.waitKey()\n",
    "cv2.destroyAllWindows()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "cv2.imwrite(outputPath, image)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "scrolled": true
   },
   "outputs": [],
   "source": [
    "############################\n",
    "############################\n",
    "############################\n",
    "############################\n",
    "#### LEGACY CODES BELOW ####\n",
    "############################\n",
    "############################\n",
    "############################\n",
    "############################"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false
   },
   "outputs": [],
   "source": [
    "#WORKING OLD VERSION: BUT CLUSMY RESULT\n",
    "#from __future__ import division\n",
    "#i=0\n",
    "#j=5\n",
    "\n",
    "SHOW_DETAIL = True\n",
    "SHOW_DETAIL = True\n",
    "\n",
    "# Sorting lines\n",
    "my_lines = page.lines\n",
    "my_lines.sort(key=lambda line:((line.start.y+line.end.y)/2,(line.start.x+line.end.x)/2))\n",
    "#my_lines[0].start.x = 2\n",
    "#my_lines[0].start.y = 0\n",
    "#my_lines[0].end.x = 6\n",
    "#my_lines[0].end.y = 0\n",
    "\n",
    "#my_lines[5].start.x = 1\n",
    "#my_lines[5].start.y = 1\n",
    "#my_lines[5].end.x = 5\n",
    "#my_lines[5].end.y = 3\n",
    "\n",
    "#my_lines[0].group = None\n",
    "#my_lines[5].group = None\n",
    "\n",
    "EPS = 3#1e-3\n",
    "group_idx = 0\n",
    "threshold_angle = 1.0\n",
    "threshold_perpendist = 1.3 * 60.0\n",
    "threshold_overlap    = 1.0\n",
    "threshold_paralldist = 1.5 * 40.0\n",
    "\n",
    "for idx_my_line, my_line in enumerate(my_lines):\n",
    "    if(idx_my_line+1 == len(my_lines)-1):\n",
    "        break\n",
    "    i = idx_my_line\n",
    "    for j in range(i+1,len(my_lines)-1):\n",
    "    #for j in range(i+1,30):\n",
    "        sameGroup = False\n",
    "        ################################\n",
    "        # CALCULATE GEOMETRIC FEATURES #\n",
    "        ################################\n",
    "        # Point setting\n",
    "        x_O_i = my_lines[i].start.x\n",
    "        #y_O_i = my_lines[i].start.y\n",
    "        y_O_i = page.image.shape[0] - my_lines[i].start.y\n",
    "        x_F_i = my_lines[i].end.x\n",
    "        #y_F_i = my_lines[i].end.y\n",
    "        y_F_i = page.image.shape[0] - my_lines[i].end.y \n",
    "\n",
    "        x_O_j = my_lines[j].start.x\n",
    "        #y_O_j = my_lines[j].start.y\n",
    "        y_O_j = page.image.shape[0] - my_lines[j].start.y\n",
    "        x_F_j = my_lines[j].end.x\n",
    "        #y_F_j = my_lines[j].end.y\n",
    "        y_F_j = page.image.shape[0] - my_lines[j].end.y\n",
    "        \n",
    "        delta_x_i = abs(x_F_i - x_O_i)\n",
    "        delta_y_i = abs(y_F_i - y_O_i)\n",
    "        delta_x_j = abs(x_F_j - x_O_j)\n",
    "        delta_y_j = abs(y_F_j - y_O_j)\n",
    "        \n",
    "        # ith or jth line is dot, so skip it\n",
    "        if ((delta_x_i == 0 and delta_y_i == 0) or (delta_x_j == 0 and delta_y_j == 0)):\n",
    "            continue\n",
    "            \n",
    "        if SHOW_DETAIL:\n",
    "            print(\"\\n****************************************************************\")\n",
    "            print(i, my_lines[i].points)\n",
    "            print(j, my_lines[j].points)\n",
    "            print(\"i:\",x_O_i,y_O_i,\"-\",x_F_i,y_F_i)\n",
    "            print(\"j:\",x_O_j,y_O_j,\"-\",x_F_j,y_F_j)\n",
    "            \n",
    "        # Calculate angle\n",
    "        theta_i_j = math.atan2(delta_y_j,delta_x_j-math.atan2(delta_y_i,delta_x_i))\n",
    "        if SHOW_DETAIL:\n",
    "            print(\"Angle:\",theta_i_j)\n",
    "\n",
    "        # Calculate overlap\n",
    "        #if delta_x_j == 0:\n",
    "        #    delta_x_j = 0.1\n",
    "        #if delta_y_i == 0:\n",
    "        #    delta_y_i = 0.1\n",
    "        #if delta_y_j == 0:\n",
    "        #    delta_y_j = 0.1\n",
    "        #if delta_x_i == 0:\n",
    "        #    delta_x_i = 0.1\n",
    "\n",
    "\n",
    "        x_A_j = (x_O_i*delta_x_i*delta_x_j + x_O_j*delta_y_i*delta_y_j + delta_x_j*delta_y_i*(y_O_i-y_O_j))/(delta_y_i*delta_y_j + delta_x_i*delta_x_j + EPS)\n",
    "        if (delta_x_j != 0):\n",
    "            y_A_j = (delta_y_j/delta_x_j)*(x_A_j - x_O_j) + y_O_j\n",
    "        else:\n",
    "            x_A_j = y_O_j\n",
    "\n",
    "        x_B_j = (x_F_i*delta_x_i*delta_x_j + x_F_j*delta_y_i*delta_y_j + delta_x_j*delta_y_i*(y_F_i-y_F_j))/(delta_y_i*delta_y_j + delta_x_i*delta_x_j + EPS)\n",
    "        if (delta_x_j != 0):\n",
    "            y_B_j = (delta_y_j/delta_x_j)*(x_A_j - x_F_j) + y_F_j\n",
    "        else:\n",
    "            x_B_j = y_F_j\n",
    "\n",
    "        x_middle_candidates = [x_O_j, x_F_j, x_A_j, x_B_j]\n",
    "        x_middle_candidates.sort()\n",
    "        y_middle_candidates = [y_O_j, y_F_j, y_A_j, y_B_j]\n",
    "        y_middle_candidates.sort()\n",
    "\n",
    "        x_C_j = x_middle_candidates[-2]\n",
    "        y_C_j = y_middle_candidates[-2]\n",
    "\n",
    "        x_D_j = x_middle_candidates[-3]\n",
    "        y_D_j = y_middle_candidates[-3]\n",
    "        if SHOW_DETAIL:\n",
    "            print(\"x_A_j,y_A_j\",x_A_j,y_A_j)\n",
    "            print(\"x_B_j,y_B_j\",x_B_j,y_B_j)\n",
    "            print(\"x_C_j,y_C_j\",x_C_j,y_C_j)\n",
    "            print(\"x_D_j,y_D_j\",x_D_j,y_D_j)\n",
    "\n",
    "        if ((x_O_j <= x_C_j <= x_F_j and y_O_j <= y_C_j <= y_F_j) or (x_O_i <= x_C_j <= x_F_i and y_O_i <= x_C_j <= y_F_i)) and ((x_O_j <= x_D_j <= x_F_j and y_O_j <= y_D_j <= y_F_j) or (x_O_i <= x_D_j <= x_F_i and y_O_i <= y_D_j <= y_F_i)):\n",
    "            overlap = True\n",
    "        else:\n",
    "            overlap = False\n",
    "        # Force to be true; no overlap is required in the default mode\n",
    "        #overlap = True\n",
    "\n",
    "        p_j = (math.sqrt(math.pow(y_D_j-y_C_j,2)+math.pow(x_D_j-x_C_j,2)))/2.0\n",
    "        l_j = math.sqrt(math.pow(y_F_j-y_O_j,2)+math.pow(x_F_j-x_O_j,2))\n",
    "        if (l_j == 0):\n",
    "            l_j = 0.1\n",
    "        if overlap:\n",
    "            p_i_j = p_j/l_j\n",
    "        else:\n",
    "            p_i_j = -p_j/l_j\n",
    "        \n",
    "        if SHOW_DETAIL:\n",
    "            print(\"Overlap?\",overlap)\n",
    "            print(\"p_j:\",p_j)\n",
    "            print(\"p_i_j:\",p_i_j)\n",
    "\n",
    "        # Calculate parallel_dist\n",
    "        if overlap:\n",
    "            d_i_j_a = p_j\n",
    "        else:\n",
    "            d_i_j_a = -p_j\n",
    "        if SHOW_DETAIL:\n",
    "            print(\"parallel_dist: \",d_i_j_a)\n",
    "\n",
    "        # Calculate perpend_dist\n",
    "        x_M_j = (x_C_j + x_D_j)/2.0\n",
    "        y_M_j = (y_C_j + y_D_j)/2.0\n",
    "        if SHOW_DETAIL:\n",
    "            print(\"x_M_j,y_M_j\",x_M_j,y_M_j)\n",
    "            print(\"delta_x_i:\",delta_x_i)\n",
    "            print(\"delta_y_i:\",delta_y_i)\n",
    "            print(\"delta_x_j:\",delta_x_j)\n",
    "            print(\"delta_y_j:\",delta_y_j)\n",
    "            \n",
    "        if delta_x_i != 0.0 and delta_x_i != 0.0:\n",
    "            d_e_i_j = ((x_M_j - x_O_i) - (y_M_j - y_O_i)*delta_x_i/(delta_y_i + EPS))/((delta_x_i**2)/(delta_y_i**2 + EPS) + 1)**0.5\n",
    "            #((x_M_j - x_O_i) - (y_M_j - y_O_i)*delta_x_i/(delta_y_i + EPS))/(math.pow(math.pow(delta_x_i,2)/math.pow(delta_y_i,2)+1,0.5) + EPS)\n",
    "        elif delta_y_i == 0.0:\n",
    "            d_e_i_j = y_M_j - y_O_i  \n",
    "        elif delta_x_i == 0.0:\n",
    "            d_e_i_j = x_M_j - x_O_i\n",
    "        d_e_i_j = abs(d_e_i_j)\n",
    "        \n",
    "        if SHOW_DETAIL:\n",
    "            print(\"perpend_dist: \",d_e_i_j)\n",
    "\n",
    "        ######################\n",
    "        # DECIDING GROUPNESS #\n",
    "        #######################\n",
    "        # 1. angle check\n",
    "        if theta_i_j < threshold_angle:\n",
    "            if SHOW_DETAIL: print(\"... Angle ok!\")\n",
    "        # 2. perpend_dist check\n",
    "            if 0 < d_e_i_j < threshold_perpendist:\n",
    "                if SHOW_DETAIL: print(\"... Perpendicular ok!\")\n",
    "        # 3.a. overlap check\n",
    "        # 3.b. parallel_dist check\n",
    "                if ((overlap and p_i_j < threshold_overlap)):\n",
    "                    if SHOW_DETAIL: print(\"... Overlap & p_i_j ok!\")\n",
    "                    # Group!\n",
    "                    sameGroup = True\n",
    "                elif (abs(d_i_j_a) < threshold_paralldist):\n",
    "                    if SHOW_DETAIL: print(\"... Parallel ok!\")\n",
    "                    # Group!\n",
    "                    sameGroup = True\n",
    "                    \n",
    "        if SHOW_DETAIL:\n",
    "            print(\"same group? \",sameGroup)\n",
    "        if sameGroup:\n",
    "            if SHOW_DETAIL:\n",
    "                print(\"before group idx: \",group_idx)\n",
    "                print(\"before i's group: \", my_lines[i].group)\n",
    "                print(\"before j's group: \", my_lines[j].group)\n",
    "            if (my_lines[i].group == None) and (my_lines[j].group == None):\n",
    "                if SHOW_DETAIL:\n",
    "                    print(\"... case 1\")\n",
    "                # Assign to a new block\n",
    "                group_idx = group_idx + 1\n",
    "                my_lines[i].group = group_idx\n",
    "                my_lines[j].group = group_idx\n",
    "            elif (my_lines[i].group == None):\n",
    "                if SHOW_DETAIL: print(\"... case 2\")\n",
    "                # Unassigned text-line is assigned to the block of the other\n",
    "                my_lines[i].group = my_lines[j].group\n",
    "            elif (my_lines[j].group == None):\n",
    "                if SHOW_DETAIL: print(\"... case 3\")\n",
    "                # Unassigned text-line is assigned to the block of the other\n",
    "                my_lines[j].group = my_lines[i].group\n",
    "            if SHOW_DETAIL: print(\"after group idx: \",group_idx)\n",
    "            if SHOW_DETAIL: print(\"after i's group: \", my_lines[i].group)\n",
    "            if SHOW_DETAIL: print(\"after j's group: \", my_lines[j].group)\n",
    "            #else:\n",
    "                # Block merge\n",
    "\n",
    "print(\"Done!\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "##############################\n",
    "# Draw BoundingBox (Polygon) #\n",
    "##############################\n",
    "import cv2\n",
    "import numpy\n",
    "image = page.image.copy()\n",
    "# point_0 (x_0, y_0) x_0:*    y_0:Max\n",
    "# point_1 (x_1, y_1) x_1:Max  y_1:*\n",
    "# point_2 (x_2, y_2) x_2:*    y_2:Min\n",
    "# point_3 (x_3, y_3) x_3:Min  y_3:*\n",
    "boundingbox_table = numpy.zeros((group_idx+1,8))  # [x_0,y_0,x_1,y_1,x_2,y_2,x_3,y_3]\n",
    "boundingbox_table[:,0] = 0  # x_0\n",
    "boundingbox_table[:,1] = 0  # y_0\n",
    "boundingbox_table[:,2] = 0  # x_1\n",
    "boundingbox_table[:,3] = 0  # y_1\n",
    "boundingbox_table[:,4] = 0  # x_2\n",
    "boundingbox_table[:,5] = image.shape[0]  # y_2\n",
    "boundingbox_table[:,6] = image.shape[1]  # x_3\n",
    "boundingbox_table[:,7] = 0  # y_3\n",
    "\n",
    "# Find BoundingBoxes for Each Group\n",
    "for my_line in my_lines:\n",
    "    for i in range(1,group_idx+1):\n",
    "        \n",
    "                \n",
    "        if my_line.group == i:\n",
    "            # Update if found new min or max\n",
    "            if my_line.start.y > boundingbox_table[i-1,1]:\n",
    "                boundingbox_table[i-1,0] = my_line.start.x\n",
    "                boundingbox_table[i-1,1] = my_line.start.y\n",
    "            if my_line.end.y > boundingbox_table[i-1,1]:\n",
    "                boundingbox_table[i-1,0] = my_line.end.x\n",
    "                boundingbox_table[i-1,1] = my_line.end.y\n",
    "                \n",
    "            if my_line.start.x > boundingbox_table[i-1,2]:\n",
    "                boundingbox_table[i-1,2] = my_line.start.x\n",
    "                boundingbox_table[i-1,3] = my_line.start.y\n",
    "            if my_line.end.y > boundingbox_table[i-1,2]:\n",
    "                boundingbox_table[i-1,2] = my_line.end.x\n",
    "                boundingbox_table[i-1,3] = my_line.end.y\n",
    "                \n",
    "            if my_line.start.y < boundingbox_table[i-1,5]:\n",
    "                boundingbox_table[i-1,4] = my_line.start.x\n",
    "                boundingbox_table[i-1,5] = my_line.start.y\n",
    "            if my_line.end.y < boundingbox_table[i-1,5]:\n",
    "                boundingbox_table[i-1,4] = my_line.end.x\n",
    "                boundingbox_table[i-1,5] = my_line.end.y\n",
    "                \n",
    "            if my_line.start.x < boundingbox_table[i-1,6]:\n",
    "                boundingbox_table[i-1,6] = my_line.start.x\n",
    "                boundingbox_table[i-1,7] = my_line.start.y\n",
    "            if my_line.end.x < boundingbox_table[i-1,6]:\n",
    "                boundingbox_table[i-1,6] = my_line.end.x\n",
    "                boundingbox_table[i-1,7] = my_line.end.y\n",
    "\n",
    "# Draw BoundingBoxes \n",
    "for i in range(group_idx+1):\n",
    "    x_0 = int(boundingbox_table[i,0])\n",
    "    y_0 = int(boundingbox_table[i,1])\n",
    "    x_1 = int(boundingbox_table[i,2])\n",
    "    y_1 = int(boundingbox_table[i,3])\n",
    "    x_2 = int(boundingbox_table[i,4])\n",
    "    y_2 = int(boundingbox_table[i,5])\n",
    "    x_3 = int(boundingbox_table[i,6])\n",
    "    y_3 = int(boundingbox_table[i,7])\n",
    "    \n",
    "    pts = numpy.array([[x_0,y_0],[x_1,y_1],[x_2,y_2],[x_3,y_3]], numpy.int32)\n",
    "    pts = pts.reshape((-1,1,2))\n",
    "    cv2.polylines(image,[pts],True,(0,0,255),5)\n",
    "\n",
    "maxDimension = Dimension(800, 800)\n",
    "displayDimension = Dimension(image.shape[1], image.shape[0])\n",
    "displayDimension.fitInside(maxDimension)\n",
    "image = cv2.resize(image, tuple(displayDimension))\n",
    "cv2.namedWindow('title', cv2.CV_WINDOW_AUTOSIZE)\n",
    "cv2.imshow('grouped', image)\n",
    "cv2.waitKey()\n",
    "cv2.destroyAllWindows()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
